<template>
  <div class="monaco" id="monaco" ref="monacoRef"></div>
</template>

<script setup>
import * as monaco from "monaco-editor";
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
import { onMounted, ref, onBeforeUnmount, watch } from "vue";

self.MonacoEnvironment = {
  getWorker(_, label) {
    if (label === "json") {
      return new jsonWorker();
    }
    if (label === "css" || label === "scss" || label === "less") {
      return new cssWorker();
    }
    if (label === "html" || label === "handlebars" || label === "razor") {
      return new htmlWorker();
    }
    if (label === "typescript" || label === "javascript") {
      return new tsWorker();
    }
    return new editorWorker();
  },
};

const props = defineProps({
  code: {
    type: String,
    required: true,
  },
  language: {
    type: String,
    default: "xml",
  },
  line: {
    type: Number,
    default: 0,
  },
});

const emit = defineEmits(["update:code"]);

const monacoRef = ref(null);
let editor = null;
let decorations = []; // 存储装饰的ID
let isUserEditing = false; // 标记用户是否正在主动编辑

const highlightLine = () => {
  const lineNumber = Number(props.line);
  if (lineNumber === 0) {
    decorations = editor.deltaDecorations(decorations, []);
    return;
  }
  decorations = editor.deltaDecorations(decorations, [
    {
      range: new monaco.Range(lineNumber, 1, lineNumber, 1),
      options: {
        isWholeLine: true,
        className: "highlight-line",
      },
    },
  ]);
};

const setLanguage = () => {
  if (!editor) {
    return;
  }
  const model = editor.getModel();
  if (!model) {
    return;
  }
  monaco.editor.setModelLanguage(model, props.language);
};

const setPosition = () => {
  if (!editor) {
    return;
  }
  editor.revealLineInCenter(Number(props.line));
};

const init = () => {
  editor = monaco.editor.create(monacoRef.value, {
    value: props.code,
    language: props.language,
    theme: "vs-dark",
    automaticLayout: true, // 自动调整大小
    lineHeight: 24,
    tabSize: 2,
    fontSize: 16,
    fontFamily: "Consolas",
    minimap: {
      // 关闭小地图
      enabled: false,
    },
    readOnly: false,
    domReadOnly: false,
  });

  // 添加代码更改事件监听
  editor.onDidChangeModelContent(() => {
    isUserEditing = true; // 标记用户正在主动编辑
    emit("update:code", editor.getValue());
  });

  // 添加焦点事件，表示用户正在交互
  editor.onDidFocusEditorText(() => {
    isUserEditing = true;
  });

  // 添加失焦事件，用户交互结束
  editor.onDidBlurEditorText(() => {
    setTimeout(() => {
      isUserEditing = false;
    }, 100);
  });
};

const assignmentCode = () => {
  if (!editor) {
    return;
  }

  // 获取当前编辑器状态
  const currentValue = editor.getValue();

  // 检查内容是否发生变化
  const contentChanged = currentValue !== props.code;

  // 内容变化时总是更新，无论是用户编辑还是标签切换
  if (contentChanged) {
    // 保存当前的滚动位置和选择状态
    const scrollTop = editor.getScrollTop();
    const scrollLeft = editor.getScrollLeft();
    const selection = editor.getSelection();

    // 判断是否是标签切换 - 通过内容变化幅度判断
    // 如果内容变化超过50%，很可能是标签切换而不是用户编辑
    const isLikelyTabSwitch =
      Math.abs(currentValue.length - props.code.length) >
      currentValue.length * 0.5;

    // 强制更新内容
    editor.setValue(props.code);

    // 在用户编辑时保留位置，标签切换时不保留
    if (selection && !isLikelyTabSwitch && isUserEditing) {
      // 恢复选择和滚动位置
      editor.setSelection(selection);
      editor.setScrollTop(scrollTop);
      editor.setScrollLeft(scrollLeft);
    } else {
      // 这可能是标签切换，重置编辑状态并滚动到顶部
      isUserEditing = false;
      // 主动设置滚动位置为顶部
      editor.setScrollTop(0);
      editor.setScrollLeft(0);
      // 将光标位置设置到文档开头
      editor.setPosition({ lineNumber: 1, column: 1 });
    }

    // 更新语言
    setLanguage();

    // 只有在指定了非零行号的情况下才滚动
    if (props.line > 0) {
      setPosition();
    }

    highlightLine();
  } else if (isUserEditing) {
    // 如果是用户编辑，只更新高亮，不跳转位置
    highlightLine();
  }
};

watch(() => props.code, assignmentCode, { immediate: true, deep: true });
watch(() => props.language, setLanguage);
watch(() => props.line, highlightLine);

onMounted(() => {
  init();

  // 监听标签切换事件
  const resetEditorStateHandler = () => {
    isUserEditing = false;

    // 在标签切换时，如果编辑器已初始化，直接滚动到顶部
    if (editor) {
      editor.setScrollTop(0);
      editor.setScrollLeft(0);
      editor.setPosition({ lineNumber: 1, column: 1 });
    }
  };

  document.addEventListener("resetEditorState", resetEditorStateHandler);

  // 保存清理函数
  onBeforeUnmount(() => {
    // 移除事件监听
    document.removeEventListener("resetEditorState", resetEditorStateHandler);

    if (editor) {
      editor.dispose();
      editor = null;
    }
  });
});
</script>

<style scoped lang="scss">
.monaco {
  width: 100%;
  height: 100%;
}
</style>

<style>
#monaco .highlight-line {
  background-color: rgba(140, 143, 255, 0.7) !important; /* 设置高亮背景颜色 */
}
</style>
